package com.suibibk.springCloud.order.controller;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/order")
public class OrderController {
    public static final  String HELLO_RESOURCE_NAME = "hello";
    public static final  String USER_RESOURCE_NAME = "user";
    public static final String BREAK_RESOURCE_NAME = "break";
    @RequestMapping("/hello")
    public String hello(){
        // 1.5.0 版本开始可以直接利用 try-with-resources 特性
        try (Entry entry = SphU.entry(HELLO_RESOURCE_NAME)) {
            // 被保护的逻辑
            return "hello world";
        } catch (BlockException ex) {
            // 处理被流控的逻辑
            return "被限流了";
        }

    }
    @PostConstruct
    private void initFlowRules(){
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource(HELLO_RESOURCE_NAME);
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // Set limit QPS to 20. 这里表示超过1秒的频率就会限流
        rule.setCount(1);
        rules.add(rule);

        FlowRule rule2 = new FlowRule();
        rule2.setResource(USER_RESOURCE_NAME);
        rule2.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // Set limit QPS to 20. 这里表示超过1秒的频率就会限流
        rule2.setCount(1);
        rules.add(rule2);
        FlowRuleManager.loadRules(rules);


        List<DegradeRule> degradeRules = new ArrayList<>();
        DegradeRule degradeRule = new DegradeRule();
        degradeRule.setResource(BREAK_RESOURCE_NAME);
        //设置规则策略，异常数
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
        //触发熔断异常数：2
        degradeRule.setCount(2);
        //触发熔断最小请求数：4
        degradeRule.setMinRequestAmount(4);
        //熔断时长，单位为秒，一旦触发了熔断，再次请求对应的接口就会直接调用降级方法，这个跟之前的流量控制还是有区别的
        //10秒过后会变成半开的状态，恢复接口请求调用，如果第一次请求异就异常，将会再次熔断
        degradeRule.setTimeWindow(10);
        degradeRule.setStatIntervalMs(60*1000);
        degradeRules.add(degradeRule);
        DegradeRuleManager.loadRules(degradeRules);

    }

    /**
     * exceptionHandler :被流控降级的方法，默认该方法必须声明在同一个类中，一定是public，返回值跟原方法一致
     * @param id
     * @return
     */
    @RequestMapping("/user")
    @SentinelResource(value = USER_RESOURCE_NAME, blockHandler = "exceptionHandler")
    public String user(String id) {
        return "返回用户成功"+id;
    }

    // Block 异常处理函数，参数最后多一个 BlockException，其余与原函数一致.
    public String exceptionHandler(String id, BlockException ex) {
        // Do some log here.
        ex.printStackTrace();
        return "被限流了"+id;
    }

    @RequestMapping("/break")
    @SentinelResource(value = BREAK_RESOURCE_NAME, blockHandler = "exceptionHandler2")
    public String breakA(String id) {
        throw new RuntimeException("报错了");
    }

    // Block 异常处理函数，参数最后多一个 BlockException，其余与原函数一致.
    public String exceptionHandler2(String id, BlockException ex) {
        // Do some log here.
       // ex.printStackTrace();
        return "被熔断了"+id;
    }


}
